package com.shangting.web.service.impl;

import com.shangting.common.constant.RedisConstant;
import com.shangting.common.entity.SystemUser;
import com.shangting.common.exception.ShangTingException;
import com.shangting.common.result.ResultCodeEnum;
import com.shangting.common.utils.JwtUtil;
import com.shangting.common.utils.RedisUtil;
import com.shangting.web.mapper.SystemUserMapper;
import com.shangting.web.security.UserDetailsImpl;
import com.shangting.web.service.LoginService;
import com.shangting.web.vo.login.CaptchaVo;
import com.shangting.web.vo.login.LoginVo;
import com.shangting.web.vo.system.user.SystemUserInfoVo;
import com.shangting.web.vo.token.TokenVo;
import com.wf.captcha.SpecCaptcha;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private SystemUserMapper systemUserMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public CaptchaVo getCaptcha() {
        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 4);
        String code = specCaptcha.text().toLowerCase();
        String key = RedisConstant.ADMIN_LOGIN_PREFIX + UUID.randomUUID();
        // 把验证码的值以 RedisConstant.ADMIN_LOGIN_PREFIX + UUID.randomUUID() 为 key 存入 redis 中
        stringRedisTemplate.opsForValue().set(key, code, RedisConstant.ADMIN_LOGIN_CAPTCHA_TTL_SEC * 100, TimeUnit.SECONDS);
        return new CaptchaVo(specCaptcha.toBase64(), key);
    }

    @Override
    public TokenVo login(LoginVo loginVo) {
        //1.判断是否输入了验证码
        if (!StringUtils.hasText(loginVo.getCaptchaCode())) {
            throw new ShangTingException(ResultCodeEnum.ADMIN_CAPTCHA_CODE_NOT_FOUND);
        }

        //2.校验验证码
        String code = stringRedisTemplate.opsForValue().get(loginVo.getCaptchaKey());
        if (code == null) {
            throw new ShangTingException(ResultCodeEnum.ADMIN_CAPTCHA_CODE_EXPIRED);
        }

        if (!code.equals(loginVo.getCaptchaCode().toLowerCase())) {
            throw new ShangTingException(ResultCodeEnum.ADMIN_CAPTCHA_CODE_ERROR);
        }

        // 生成一个包含账号密码的认证信息
        Authentication token = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
        // AuthenticationManager校验这个认证信息，返回一个已认证的Authentication
        // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
        Authentication authentication = authenticationManager.authenticate(token);
        // 将返回的Authentication存到上下文中
        SecurityContextHolder.getContext().setAuthentication(authentication);
        UserDetailsImpl loginUser = (UserDetailsImpl) authentication.getPrincipal();
        Long userId = loginUser.getSysUser().getId();
        //authenticate存入redis
        redisUtil.setCacheObject("login:" + userId, loginUser);
        //6.创建并返回TOKEN
        String accessToken = JwtUtil.createAccessToken(userId, loginUser.getUsername());
        String refreshToken = JwtUtil.createRefreshToken(userId, loginUser.getUsername());
        return new TokenVo(accessToken, refreshToken);
    }

    @Override
    public SystemUserInfoVo getLoginUserInfo(Long userId) {
        SystemUser systemUser = systemUserMapper.selectById(userId);
        SystemUserInfoVo systemUserInfoVo = new SystemUserInfoVo();
        systemUserInfoVo.setName(systemUser.getName());
        systemUserInfoVo.setAvatarUrl(systemUser.getAvatarUrl());
        return systemUserInfoVo;
    }
}
